﻿using System;
using System.IO.Ports;
using System.Threading;
using NetworkSerialPort.Helper.TcpSocket;
using oModbus.Utility;
using ILog = Sample.Helper.ILog;

namespace NetworkSerialPort
{
    /// <summary>
    /// 网络初始化 枚举
    /// </summary>
    public enum NetworkSerialClienInit
    {
        Success,
        NetworFail,
        SerialFail
    }

    public class NetworkSerialClient
    {     /// <summary>
          /// 通信
          /// </summary>
        private TcpClient _commun;
        /// <summary>
        /// ip
        /// </summary>
        private readonly string _ip;
        /// <summary>
        /// 端口
        /// </summary>
        private readonly int _port;

        //  public short KeepAlive { get; set; }
        /// <summary>
        /// 日志管理器
        /// </summary>
        protected readonly ILog LogManager;
        /// <summary>
        /// 日志事件
        /// </summary>
        public event Action<string, string> LogEvent;
        protected virtual void Log(string title, string message)
        {
            LogManager?.Info(title, message);
            LogEvent?.Invoke(title, message);
        }

        //  private readonly ITransmission _transmission;
        private readonly SerialPort _serialPort;
        public NetworkSerialClient(string ip, int port, SerialPort serialPort, ILog log = null)
        {
            _ip = ip;
            _port = port;
            LogManager = log;
            _serialPort = serialPort;

            _serialPort.DataReceived += SP_DataReceived;

            //_transmission = new SerialTransmission(serialPort);
            // _transmission.ReceivedMessageEvent += _transmission_ReceivedMessageEvent;
            //KeepAlive = keepAlive;
        }
        /// <summary>
        /// 串口占用标志位
        /// </summary>
        private readonly Mutex _stoping = new Mutex();
        private void SP_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            try
            {
                //申请
                _stoping.WaitOne();
                Thread.Sleep(1000);
                int n = _serialPort.BytesToRead;
                var data = new byte[n];
                _serialPort.Read(data, 0, n);
                //释放 
                _stoping.ReleaseMutex();

                Send(data);
                Log("接受数据 串口", data.GetHexString());
            }
            catch (Exception ex)
            {
                LogManager.Error(ex);
            }
        }


        private void _commun_ReceiveEvent(byte[] data)
        {
            try
            {
                if (data != null)
                {
                    Log("接受数据 网络", data.GetHexString());
                    _stoping.WaitOne();

                    _serialPort.Write(data, 0, data.Length);

                    //释放 
                    _stoping.ReleaseMutex();
                }
                else
                {
                    Log("接受数据 网络", "空数据");
                }

            }
            catch (Exception ex)
            {
                LogManager.Error(ex);
            }

        }

        public NetworkSerialClienInit Connection()
        {
            NetworkSerialClienInit result;
            if (_commun == null)
            {
                _commun = new TcpClient(_ip, _port, 1, true);
                _commun.ReceiveEvent += _commun_ReceiveEvent;
            }
            if (_commun.TryConnect())
            {
                try
                {
                    _serialPort.Open();
                    result = NetworkSerialClienInit.Success;
                }
                catch (Exception)
                {
                    Close();
                    result = NetworkSerialClienInit.SerialFail;
                }
            }
            else
            {
                result = NetworkSerialClienInit.NetworFail;
            }
            return result;
        }

        public bool Send(byte[] data)
        {
            try
            {
                return _commun.Send(data);
            }
            catch (Exception ex)
            {
                LogManager.Error(ex);
            }
            return false;
        }

        public bool Close()
        {
            _commun.Stop();
            return true;
        }
    }
}
